import java.util.ArrayList;
import java.util.List;

import org.omg.CORBA.BooleanHolder;
import org.omg.CORBA.ORB;
import org.omg.CORBA.StringHolder;

import common.CommonTools;
import common.Player;
import player.playerService;
import player.playerServiceHelper;
import player.playerServicePOA;

public class PlayerServiceImpl extends playerServicePOA {

	private String serverGeolocation;

	protected PlayerServiceImpl(String serverGeolocation) {
		super();
		this.serverGeolocation = serverGeolocation;
	}

	@Override
	public void createPlayerAccount(String firstName, String lastName,
			short age, String userName, String password, String iPAddress,BooleanHolder result,
			StringHolder status) {

		Player playerNew = new Player(firstName, lastName, age, userName,
				password, iPAddress);

		if (!CommonTools.isLegalIpAddress(iPAddress, serverGeolocation)) {

			CommonTools.writeLog("server", serverGeolocation,
					"Create player : Wrong IP Address:" + playerNew, "server");		
			status.value = "server" + serverGeolocation + "Create player :  Wrong IP Address:"
					+ playerNew;
			result.value = false;
			return;
		}

		List<Player> list = getList(userName);
		String key = userName.substring(0, 1).toUpperCase();
		PlayerHashTable hashTable = PlayerHashTable.getInstance();
		ArrayList semaphores = PlayerHashTable.getListsemaphores();
		int keyIndex = semaphores.indexOf(key);
		keyIndex = (keyIndex < 0) ? 0 : keyIndex;
		synchronized (semaphores.get(keyIndex)) {
			if (list == null) {
				list = new ArrayList<Player>();
				hashTable.put(key, list);
			}
			for (int i = 0; i < list.size(); i++) {
				Player p = list.get(i);
				if (p.getUserName().equals(playerNew.getUserName())) {

					CommonTools.writeLog("server", serverGeolocation,
							"Create player : Account is already created:" + playerNew, "server");
					

					status.value = "server" + serverGeolocation
							+ "Create player :  Account is already createds:" + playerNew;
					result.value = false;
					return;
				}
			}

			list.add(playerNew);
		}
		CommonTools.writeLog("server", serverGeolocation, "1 Account created: "
				+ playerNew, "server");
		status.value = "1 server" + serverGeolocation + " Account created: "
				+ playerNew;
		result.value = true;
		return;
	}

	@Override
	public void playerSignIn(String userName, String password,
			String iPAddress,BooleanHolder result, StringHolder status) {
		Player playerNew = new Player(" ", " ", 0, userName, password,
				iPAddress);
		if (!CommonTools.isLegalIpAddress(iPAddress, serverGeolocation)) 
		{
			CommonTools.writeLog("server", serverGeolocation,
					"Sign in : Wrong IP Address:" + playerNew, "server");		
			status.value = "server" + serverGeolocation + "Sign in : Wrong IP Address:"
					+ playerNew;
			result.value = false;
			return;
		}
		boolean userExist = false;
		List<Player> list = getList(userName);
		if (list == null) {
			CommonTools.writeLog("server", serverGeolocation,
					"Sign in :  Player Does not exit:empty list " + playerNew, "server");
			CommonTools.writeLog(userName, serverGeolocation,
					"Sign in : Player Does not exit:empty list " + playerNew, "server");
			status.value = "server" + serverGeolocation
					+ "Sign in :  Player Does not exit: empty list " + playerNew;
			result.value = false;
			return;
		}
		synchronized (list) {
			for (int i = 0; i < list.size(); i++) {
				Player p = list.get(i);
				if (p.getUserName().equals(userName)
						&& p.getPassword().equals(password)
						&& p.getIPAddress().equals(iPAddress)) {
					userExist = true;
					if (!p.isOnline()) {
						p.setOnline(true);

						CommonTools.writeLog("server", serverGeolocation,
								"Sign in :  Player Signed in: " + playerNew, "server");

						CommonTools.writeLog(userName, serverGeolocation,
								"Sign in :  Player Signed in: " + playerNew, "server");
						status.value = "server" + serverGeolocation
								+ " Player Signed in: " + playerNew;
						result.value = true;
						

					} else {

						CommonTools.writeLog("server", serverGeolocation,
								"Sign in : Player is already online: " + playerNew, "server");
						CommonTools.writeLog(userName, serverGeolocation,
								"Sign in :  Player is already online: " + playerNew, "server");
						status.value = "server" + serverGeolocation
								+ "Sign in :  Player is already online: " + playerNew;
						result.value = false;
					}
					return;
				}
			}
		}
		if (!userExist) {

			CommonTools.writeLog("server", serverGeolocation,
					"Sign in :  Player Does not exit userName: " + playerNew, "server");
			CommonTools.writeLog(userName, serverGeolocation,
					"Sign in :  Player Does not exit userName: " + playerNew, "server");
			status.value = "server" + serverGeolocation
					+ "Sign in :  Player Does not exit:  " + playerNew;
			result.value = false;
			return;
		}
	}

	@Override
	public void playerSignOut(String userName, String iPAddress,BooleanHolder result,
			StringHolder status) {

		Player playerNew = new Player(" ", " ", 0, userName, " ", iPAddress);

		if (!CommonTools.isLegalIpAddress(iPAddress, serverGeolocation)) {
			CommonTools.writeLog("server", serverGeolocation,
					"Sign out :  Wrong IP Address:" + playerNew, "server");
		
			status.value = "server" + serverGeolocation + "Sign out :  Wrong IP Address:"
					+ playerNew;
			result.value = false;
			return;
		}
		boolean userExist = false;
		List<Player> list = getList(userName);
		if (list == null) {
			CommonTools.writeLog("server", serverGeolocation,
					"Sign out : Player Does not exit: empty list " + playerNew, "server");
			CommonTools.writeLog(userName, serverGeolocation,
					"Sign out : Player Does not exit: empty list " + playerNew, "server");
			status.value = "server" + serverGeolocation
					+ "Sign out :  Player Does not exit: empty list" + playerNew;
			result.value = false;
			return;
		}
		// System.out.println("before synchro");
		synchronized (list) {
			for (int i = 0; i < list.size(); i++) {
				Player p = list.get(i);
				if (p.getUserName().equals(userName)
						&& p.getIPAddress().equals(iPAddress)) {
					userExist = true;
					if (p.isOnline()) {
						p.setOnline(false);
						
						CommonTools.writeLog("server", serverGeolocation,
								"Sign out : Player Signed out: " + playerNew, "server");
						CommonTools.writeLog(userName, serverGeolocation,
								"Sign out : Player Signed out: " + playerNew, "server");
						status.value = "server" + serverGeolocation
								+ "Sign out :  Player Signed out: " + playerNew;
						result.value = true;

					} else {
						System.out.println("Player is not online");
						CommonTools.writeLog("server", serverGeolocation,
								"Sign out : Player is not online: " + playerNew, "server");
						CommonTools.writeLog(userName, serverGeolocation,
								"Sign out : Player is not online: " + playerNew, "server");
						status.value = "server" + serverGeolocation
								+ "Sign out : Player is not online: " + playerNew;
						result.value = false;
						return;

					}
					return;
				}
			}
		}
		if (!userExist) {
	
			CommonTools.writeLog("server", serverGeolocation,
					"Sign out : Player Does not exit: " + playerNew, "server");
			CommonTools.writeLog(userName, serverGeolocation,
					"Sign out : Player Does not exit: " + playerNew, "server");
			status.value = "server" + serverGeolocation
					+ "Sign out : Player Does not exit:  " + playerNew;
			result.value = false;
			return;

		}
	}

	@Override
	public void transferAccount(String userName, String password,String oldIPAddress, String newIPAddress,BooleanHolder result, StringHolder status) 
	{
		Player player = new Player(" ", " ", 0, userName, " ", oldIPAddress);
		
		CommonTools.writeLog("server", serverGeolocation,
				"we got a call for transferAccount:" + newIPAddress, "server");
		
		if (!CommonTools.isLegalIpAddress(oldIPAddress, serverGeolocation)) {
			CommonTools.writeLog("server", serverGeolocation,
					"transferAccount: Wrong IP Address:" + player, "server");
			
			status.value = "server" + serverGeolocation + "transferAccount: Wrong IP Address:"
					+ player;
			result.value = false;
			return;
		}
		String newIPHead = newIPAddress.substring(0, newIPAddress.indexOf("."));
		String oldIPHead = oldIPAddress.substring(0, oldIPAddress.indexOf("."));
		
		if ((!newIPHead.equals("132")) && (!newIPHead.equals("93"))
				&& (!newIPHead.equals("182"))) 
		{
			CommonTools.writeLog("server", serverGeolocation,
					"transferAccount: new IP Address is wrong:" + newIPAddress, "server");
		
			status.value = "server" + serverGeolocation + "transferAccount: Wrong IP Address:"
					+ newIPAddress;
			result.value = false;
			return;
		}
		if (newIPHead.equals(oldIPHead))				
		{
			CommonTools.writeLog("server", serverGeolocation,
					"transferAccount: new server is equal to the old one: no transfer required" + newIPAddress, "server");
		
			status.value = "server" + serverGeolocation + "transferAccount: new server is equal to the old one: no transfer required"
					+ newIPAddress;
			result.value = false;
			return;
		}		
		List<Player> list = getList(userName);		
		
		if (list == null) {
			CommonTools.writeLog("server", serverGeolocation,
					"transferAccount:  Player Does not exit: empty list " + player, "server");
			CommonTools.writeLog(userName, serverGeolocation,
					"transferAccount: Player Does not exit: empty list " + player, "server");
			status.value = "server" + serverGeolocation
					+ "transferAccount:  Player Does not exit:empty list " + player;
			result.value = false;
			return;
		}
		boolean userExist = false;
		ArrayList semaphores = PlayerHashTable.getListsemaphores();
		String key = userName.substring(0, 1).toUpperCase();
		int keyIndex = semaphores.indexOf(key);
		keyIndex = (keyIndex < 0) ? 0 : keyIndex;
		synchronized (semaphores.get(keyIndex)) {
			for (int i = 0; i < list.size(); i++) {
				Player p = list.get(i);
				if (p.getUserName().equals(userName)) {
					userExist = true;
					if (!password.equals(p.getPassword())) {
						
						CommonTools.writeLog("server", serverGeolocation,
								"transferAccount: password is wrong: " + player, "server");
						CommonTools.writeLog(userName, serverGeolocation,
								"transferAccount: password is wrong: " + player, "server");
						status.value = "transferAccount: password is wrong: " + player;
						result.value = false;
						return;
					} else if (!oldIPAddress.equals(p.getIPAddress())) {
						
						CommonTools.writeLog("server", serverGeolocation,
								"transferAccount: ipAddress is wrong: " + player, "server");
						CommonTools.writeLog(userName, serverGeolocation,
								"transferAccount: ipAddress is wrong: " + player, "server");
						status.value = "transferAccount: ipAddress is wrong: " + player;
						result.value = false;
						return;
						
					} else {
						// send the creation to the new server
						// get the creation status from the new server
						// delete the account from the actual server
						String creationStatus = null;
						 if (sendAccountCreation(p.getFirstName(), p.getLastName(),(short) p.getAge(), p.getUserName(), p.getPassword(),newIPAddress, creationStatus ))
						 {
							 list.remove(p);
							 
							 CommonTools.writeLog("server", serverGeolocation,
										"transferAccount:  Account transfered " + player, "server");
							 CommonTools.writeLog(userName, serverGeolocation,
										"transferAccount:  Account transfered  " + player, "server");
							 status.value = "transferAccount:  Account transfered  " + player; 
							 result.value = true;
							
						 } else
						 {
							 CommonTools.writeLog("server", serverGeolocation,
										"transferAccount: "+ creationStatus +" : " + player, "server");
							 CommonTools.writeLog(userName, serverGeolocation,
										"transferAccount: "+ creationStatus + " : " + player, "server");
							 status.value = "transferAccount: "+ creationStatus + " : " + player; 
							 result.value = false;
						 }
						
						return;
					}
				}
			}
		}
		if (!userExist) {
			System.out.println("transferAccount: Player Does not exit");
			CommonTools.writeLog("server", serverGeolocation,
					"transferAccount: Player Does not exit: " + player, "server");
			CommonTools.writeLog(userName, serverGeolocation,
					"transferAccount: Player Does not exit: " + player, "server");
			status.value = "server" + serverGeolocation
					+ "transferAccount: Player Does not exit:  " + player;
			result.value = false;
			return;
		}

	}
	
	private boolean sendAccountCreation(String firstName, String lastName,short age, String userName, String password, String iPAddress, String status) 
	{
		String[] dummyArray = new String[1];		
		ORB orbEU = ORB.init(dummyArray, null);
		ORB orbAS = ORB.init(dummyArray, null);
		ORB orbNA = ORB.init(dummyArray, null);
		String playerIOR_EU = CommonTools.getIOR("player", "EU","server");
		String playerIOR_AS = CommonTools.getIOR("player", "AS","server");
		String playerIOR_NA = CommonTools.getIOR("player", "NA","server");
		
		System.out.println("EU IOR: "+playerIOR_EU);
		
		org.omg.CORBA.Object playerServiceObjectEU = orbEU.string_to_object(playerIOR_EU);
		org.omg.CORBA.Object playerServiceObjectAS = orbAS.string_to_object(playerIOR_AS);
		org.omg.CORBA.Object playerServiceObjectNA = orbNA.string_to_object(playerIOR_NA);		
				
		playerService playerService;
		
		if (CommonTools.isLegalIpAddress(iPAddress, "EU")){
			playerService = playerServiceHelper.narrow(playerServiceObjectEU);
					
		}else  if (CommonTools.isLegalIpAddress(iPAddress, "AS"))
		{
			playerService = playerServiceHelper.narrow(playerServiceObjectAS);
			
		}else
		{
			playerService = playerServiceHelper.narrow(playerServiceObjectNA);
		}		
		
		Player player = new Player(firstName, lastName, age, userName,password, iPAddress);
		
		 CommonTools.writeLog("server", serverGeolocation,
					"create player: " + player, "server");
		StringHolder statusOut = new StringHolder();
		BooleanHolder result = new BooleanHolder();
		playerService.createPlayerAccount(firstName, lastName,(short) age, userName, password, iPAddress, result, statusOut);
				
		return result.value;
		
	}

	private List getList(String userName) {
		String key = userName.substring(0, 1).toUpperCase();

		PlayerHashTable hashTable = PlayerHashTable.getInstance();

		List<Player> list = (List<Player>) hashTable.get(key);
		return list;
	}
}
